﻿using StackExchange.Redis;

namespace HelperLibrary;

public class RedisHelper : IDisposable
{
    //连接字符串
    private string _connectionString;
    //实例名称
    private string _instanceName;
    //默认数据库
    private int _defaultDB;

    private ConcurrentDictionary<string, ConnectionMultiplexer> _connections;
    public RedisHelper(string connectionString, string instanceName, int defaultDB = 0)
    {
        _connectionString = connectionString;
        _instanceName = instanceName;
        _defaultDB = defaultDB;
        _connections = new ConcurrentDictionary<string, ConnectionMultiplexer>();
    }

    /// <summary>
    /// 获取ConnectionMultiplexer
    /// </summary>
    /// <returns></returns>
    private ConnectionMultiplexer GetConnect()
    {
        return _connections.GetOrAdd(_instanceName, p => ConnectionMultiplexer.Connect(_connectionString));
    }

    /// <summary>
    /// 获取数据库
    /// </summary>
    /// <param name="configName"></param>
    /// <param name="db">默认为0：优先代码的db配置，其次config中的配置</param>
    /// <returns></returns>
    public IDatabase GetDatabase()
    {
        return GetConnect().GetDatabase(_defaultDB);
    }

    public IServer GetServer(int endPointsIndex = 0)
    {
        var confOption = ConfigurationOptions.Parse(_connectionString);
        return GetConnect().GetServer(confOption.EndPoints[endPointsIndex]);
    }

    public ISubscriber GetSubscriber()
    {
        return GetConnect().GetSubscriber();
    }
    public void Dispose()
    {
        if (_connections != null && _connections.Count > 0)
        {
            foreach (var item in _connections.Values)
            {
                item.Close();
            }
        }
    }
    public bool SetString<T>(string key, string value, TimeSpan? expiryTime = null)
    {
        if (key == null)
            throw new ArgumentNullException(nameof(key));
        if (value == null)
            throw new ArgumentNullException(nameof(value));

        // 使用连接的IDatabase接口来存储键值对并设置过期时间
        var db = GetDatabase();
        db.StringSet(key, value, expiryTime);
        return Exists(key);
    }
    public async Task<bool> SetStringAsync<T>(string key, string value, TimeSpan? expiryTime = null)
    {
        if (key == null)
            throw new ArgumentNullException(nameof(key));
        if (value == null)
            throw new ArgumentNullException(nameof(value));

        // 使用连接的IDatabase接口来存储键值对并设置过期时间
        var db = GetDatabase();
        await db.StringSetAsync(key, value, expiryTime);
        return await ExistsAsync(key);
    }
    public bool Set<T>(string key, T value, TimeSpan? expiryTime = null)
    {
        if (key == null)
            throw new ArgumentNullException(nameof(key));
        if (value == null)
            throw new ArgumentNullException(nameof(value));
        // 将对象序列化为字符串，然后存储到Redis中
        var serializedValue = JsonConvert.SerializeObject(value);

        // 使用连接的IDatabase接口来存储键值对并设置过期时间
        var db = GetDatabase();
        db.StringSet(key, serializedValue, expiryTime);
        return Exists(key);
    }
    public async Task<bool> SetAsync<T>(string key, T value, TimeSpan? expiryTime = null)
    {
        if (key == null)
            throw new ArgumentNullException(nameof(key));
        if (value == null)
            throw new ArgumentNullException(nameof(value));
        // 将对象序列化为字符串，然后存储到Redis中
        var serializedValue = JsonConvert.SerializeObject(value);

        // 使用连接的IDatabase接口来存储键值对并设置过期时间
        var db = GetDatabase();
        await db.StringSetAsync(key, serializedValue, expiryTime);
        return await ExistsAsync(key);
    }

    /// <summary>
    /// 获取缓存
    /// </summary>
    /// <param name="key">缓存Key</param>
    /// <returns></returns>
    public string? GetString(string key)
    {
        if (key == null)
            return "";
        if (!Exists(key))
        {
            return "";
        }
        var db = GetDatabase();
        if (db == null)
        {
            return "";
        }
        var value = db.StringGet(key);
        if (value.IsNullOrEmpty)
        {
            return "";
        }
        return value;
    }
    /// <summary>
    /// 获取缓存
    /// </summary>
    /// <param name="key">缓存Key</param>
    /// <returns></returns>
    public async Task<string?> GetStringAsync(string key)
    {
        if (key == null)
            return default;
        if (!await ExistsAsync(key))
        {
            return default;
        }
        var db = GetDatabase();
        return await db.StringGetAsync(key);
    }

    /// <summary>
    /// 获取缓存
    /// </summary>
    /// <param name="key">缓存Key</param>
    /// <returns></returns>
    public T? Get<T>(string key)
    {
        if (key == null)
            return default;
        if (!Exists(key))
        {
            return default;
        }
        var db = GetDatabase();
        if (db == null)
        {
            return default;
        }
        var value = db.StringGet(key);
        if (value.IsNullOrEmpty)
        {
            return default;
        }
        return JsonConvert.DeserializeObject<T>(value);
    }
    /// <summary>
    /// 获取缓存
    /// </summary>
    /// <param name="key">缓存Key</param>
    /// <returns></returns>
    public async Task<T?> GetAsync<T>(string key)
    {
        if (key == null)
            return default;
        if (!await ExistsAsync(key))
        {
            return default;
        }
        var db = GetDatabase();
        return JsonConvert.DeserializeObject<T>(await db.StringGetAsync(key));
    }

    /// <summary>
    /// 获取缓存
    /// </summary>
    /// <param name="key">缓存Key</param>
    /// <returns></returns>
    public async Task<object?> GetAsync(string key)
    {
        if (key == null)
            return null;
        if (!await ExistsAsync(key))
        {
            return null;
        }
        var db = GetDatabase();
        return JsonConvert.DeserializeObject<object>(db.StringGetAsync(key).ToString());
    }

    /// <summary>
    /// 验证缓存项是否存在
    /// </summary>
    /// <param name="key">缓存Key</param>
    /// <returns></returns>
    public async Task<bool> ExistsAsync(string key)
    {
        if (key == null)
            throw new ArgumentNullException(nameof(key));
        var db = GetDatabase();
        return await db.KeyExistsAsync(key);
    }

    /// <summary>
    /// 验证缓存项是否存在
    /// </summary>
    /// <param name="key">缓存Key</param>
    /// <returns></returns>
    public bool Exists(string key)
    {
        if (key == null)
            throw new ArgumentNullException(nameof(key));
        var db = GetDatabase();
        return db.KeyExists(key);
    }
    /// <summary>
    /// 移除某个缓存项
    /// </summary>
    /// <param name="key">缓存Key</param>
    /// <returns></returns>
    public bool Remove(string key)
    {
        if (key == null)
            throw new ArgumentNullException(nameof(key));
        var db = GetDatabase();
        return db.KeyDelete(key);
    }
    /// <summary>
    /// 移除某个缓存项
    /// </summary>
    /// <param name="key">缓存Key</param>
    /// <returns></returns>
    public async Task<bool> RemoveAsync(string key)
    {
        if (key == null)
            throw new ArgumentNullException(nameof(key));
        var db = GetDatabase();
        return await db.KeyDeleteAsync(key);
    }
}